# 【示例10.5】第十章 10.1 小节 main_test.py
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import text

from sql_app.database import Base
from main import app, get_db

# 创建测试数据库引擎和会话
engine = create_engine("mysql://root:12345678@localhost/cat_test")
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 在模块级别创建表（只执行一次）
Base.metadata.create_all(bind=engine)

@pytest.fixture(scope="function")
def test_db():
    """为每个测试函数提供独立的数据库会话"""
    db = TestingSessionLocal()
    
    # 开始事务
    transaction = db.begin_nested()  # 使用嵌套事务，更安全
    
    try:
        yield db
    except Exception:
        # 发生异常时回滚
        transaction.rollback()
        raise
    finally:
        # 安全地关闭会话
        try:
            # 检查事务是否活跃
            if transaction.is_active:
                transaction.rollback()
            db.close()
        except Exception:
            pass  # 忽略关闭时的异常

@pytest.fixture(scope="function")
def client(test_db):
    """为每个测试函数提供测试客户端"""
    def override_get_db():
        try:
            yield test_db
        finally:
            pass  # 不关闭会话，由test_db fixture处理
    
    # 替换依赖项
    app.dependency_overrides[get_db] = override_get_db
    client = TestClient(app)
    
    yield client
    
    # 清理依赖项重写
    app.dependency_overrides.clear()

def test_create_user(client):
    """测试创建用户"""
    response = client.post(
        "/users/",
        json={"email": "cnanyi@qq.com", "password": "123456"},
    )
    assert response.status_code == 200, response.text
    data = response.json()
    assert data["email"] == "cnanyi@qq.com"
    assert "id" in data

def test_create_duplicate_user(client):
    """测试创建重复用户"""
    # 第一次创建应该成功
    response1 = client.post(
        "/users/",
        json={"email": "duplicate@qq.com", "password": "123456"},
    )
    assert response1.status_code == 200
    
    # 第二次创建相同邮箱应该失败
    response2 = client.post(
        "/users/",
        json={"email": "duplicate@qq.com", "password": "123456"},
    )
    assert response2.status_code == 400
    assert "Email already registered" in response2.text

def test_get_users(client):
    """测试获取用户列表"""
    # 先创建一个用户
    client.post(
        "/users/",
        json={"email": "test@example.com", "password": "123456"},
    )
    
    # 获取用户列表
    response = client.get("/users/")
    assert response.status_code == 200
    users = response.json()
    assert isinstance(users, list)

def test_get_user_by_id(client):
    """测试通过ID获取用户"""
    # 先创建一个用户
    create_response = client.post(
        "/users/",
        json={"email": "getbyid@example.com", "password": "123456"},
    )
    user_id = create_response.json()["id"]
    
    # 通过ID获取用户
    response = client.get(f"/users/{user_id}")
    assert response.status_code == 200
    user = response.json()
    assert user["id"] == user_id
    assert user["email"] == "getbyid@example.com"

# mysql -u root -p
# 12345678
# -- 连接到MySQL并执行以下命令
# DROP DATABASE IF EXISTS cat_test;
# CREATE DATABASE cat_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# mysql> exit;
# pytest .\main_test.py -v